package com.zhihu.matisse;

import com.zhihu.matisse.component.AlbumsSpinner;
import com.zhihu.matisse.component.CheckRadioView;
import com.zhihu.matisse.listener.LoaderCallback;
import com.zhihu.matisse.loader.AlbumLoader;
import com.zhihu.matisse.loader.ResultSetLoader;
import com.zhihu.matisse.model.Album;
import com.zhihu.matisse.model.Item;
import com.zhihu.matisse.model.SelectedItemCollection;
import com.zhihu.matisse.model.SelectionSpec;
import com.zhihu.matisse.provider.AlbumsAdapter;
import com.zhihu.matisse.provider.MediaProvider;
import com.zhihu.matisse.slice.AlbumPreviewAbility;
import com.zhihu.matisse.slice.BasePreviewAbility;
import com.zhihu.matisse.slice.CameraAbility;
import com.zhihu.matisse.slice.SelectPreviewAbility;
import com.zhihu.matisse.utils.IncapableDialog;
import com.zhihu.matisse.utils.L;
import com.zhihu.matisse.utils.PhotoMetadataUtils;

import com.zhihu.matisse.utils.UIUtils;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.utils.Color;
import ohos.data.resultset.ResultSet;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.PacMap;
import ohos.utils.net.Uri;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;

import static com.zhihu.matisse.model.SelectedItemCollection.STATE_COLLECTION_TYPE;
import static com.zhihu.matisse.model.SelectedItemCollection.STATE_SELECTION;

public class MatisseAbility extends Ability implements
        AlbumsSpinner.OnItemSelectedListener,
        MediaProvider.OnMediaClickListener,
        MediaProvider.CheckStateListener {
    public static final String EXTRA_RESULT_SELECTION = "extra_result_selection";
    public static final String EXTRA_RESULT_SELECTION_PATH = "extra_result_selection_path";
    public static final String EXTRA_RESULT_ORIGINAL_ENABLE = "extra_result_original_enable";
    public static final int REQUEST_CODE_PREVIEW = 23;
    public static final int RESULT_OK = 204;
    public static final String CHECK_STATE = "checkState";

    private Image ivBack;
    private Text tvTitle;
    private Text tvPreview;
    private Text tvApply;

    private ListContainer listContainer;
    private DirectionalLayout emptyLayout;
    private DirectionalLayout dlCheck;
    private CheckRadioView checkRadioView;
    private Text textCheck;
    private final SelectedItemCollection mSelectedCollection = new SelectedItemCollection(this);
    private SelectionSpec mSpec;
    private ResultSetLoader loader;
    private AlbumLoader albumLoader;
    private MediaProvider provider;
    private AlbumsAdapter albumsAdapter;
    private AlbumsSpinner albumsSpinner;

    private boolean mOriginalEnable = false;

    private int mSelectedColor = 0x1E8AE8;
    private int mUnSelectUdColor = 0x808080;
    private final ArrayList<Item> list = new ArrayList<>();
    private final ArrayList<Album> albums = new ArrayList<>();

    private Album album;

    @Override
    public void onStart(Intent intent) {
        mSpec = SelectionSpec.getInstance();
        if (!mSpec.hasInited) {
            terminateAbility(0);
            return;
        }
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_matisse);

        try {
            getWindow().setStatusBarColor(getResourceManager().getElement(ResourceTable.Color_zhihu_primary_dark).getColor());
        } catch (IOException | NotExistException | WrongTypeException e) {
            getWindow().setStatusBarColor(Color.WHITE.getValue());
        }
        if (mSpec.needOrientationRestriction()){
            setDisplayOrientation(mSpec.orientation);
        }

        ivBack = (Image) findComponentById(ResourceTable.Id_imageMatisse_back);
        tvTitle = (Text) findComponentById(ResourceTable.Id_textMatisse_title);
        tvPreview = (Text) findComponentById(ResourceTable.Id_textMatisse_preview);
        tvApply = (Text) findComponentById(ResourceTable.Id_textMatisse_apply);
        listContainer = (ListContainer) findComponentById(ResourceTable.Id_listMatisse);
        emptyLayout = (DirectionalLayout) findComponentById(ResourceTable.Id_emptyMatisse);
        dlCheck = (DirectionalLayout) findComponentById(ResourceTable.Id_dlCheckMatisse);
        checkRadioView = (CheckRadioView) findComponentById(ResourceTable.Id_checkMatisse_check);
        textCheck = (Text) findComponentById(ResourceTable.Id_textMatisse_check);

        int spanCount;
        SelectionSpec selectionSpec = SelectionSpec.getInstance();
        if (selectionSpec.gridExpectedSize > 0) {
            spanCount = UIUtils.spanCount(getContext(), selectionSpec.gridExpectedSize);
        } else {
            spanCount = selectionSpec.spanCount;
        }

        TableLayoutManager layoutManager = new TableLayoutManager();
        layoutManager.setColumnCount(spanCount);

        listContainer.setLayoutManager(layoutManager);

        mSelectedCollection.onCreate(null);
        provider = new MediaProvider(getContext(), list, mSelectedCollection,spanCount);
        provider.registerCheckStateListener(MatisseAbility.this);
        listContainer.setItemProvider(provider);

        albumsAdapter = new AlbumsAdapter(this, albums);
        albumsSpinner = new AlbumsSpinner(this, tvTitle);
        albumsSpinner.setOnItemSelectedListener(this);
        albumsSpinner.setSelectedTextView(tvTitle);
        albumsSpinner.setAdapter(albumsAdapter);

        albumLoader = new AlbumLoader(this);
        albumLoader.load();
        albumLoader.setLoaderCallback(albumCallback);

        provider.registerOnMediaClickListener(MatisseAbility.this);

        try {
            mSelectedColor = getContext().getResourceManager().getElement(ResourceTable.Color_zhihu_item_checkCircle_backgroundColor).getColor();
            mUnSelectUdColor = getContext().getResourceManager().getElement(ResourceTable.Color_zhihu_check_original_radio_disable).getColor();
        } catch (IOException | NotExistException | WrongTypeException e) {
            L.d(e.getMessage());
        }
        updateBottomToolbar();

        ivBack.setClickedListener(this::clickListener);
        tvPreview.setClickedListener(this::clickListener);
        tvApply.setClickedListener(this::clickListener);
        dlCheck.setClickedListener(this::clickListener);
    }

    @Override
    public void onSaveAbilityState(PacMap outState) {
        super.onSaveAbilityState(outState);
        mSelectedCollection.onSaveInstanceState(outState);
        outState.putBooleanValue("checkState", mOriginalEnable);
    }

    private final LoaderCallback<ResultSet> albumCallback = new LoaderCallback<ResultSet>() {
        @Override
        public void setCallback(ResultSet resultSet) {
            handler.postTask(new Runnable() {
                @Override
                public void run() {
                    resultSet.goToFirstRow();
                    Album album = Album.valueOf(resultSet);
                    ArrayList<Album> albumArrayList = new ArrayList<>();

                    do {
                        Album a = Album.valueOf(resultSet);
                        albumArrayList.add(a);

                    } while (resultSet.goToNextRow());

                    if (albumArrayList.isEmpty()) {
                        return;
                    }
                    resultSet.close();
                    albums.clear();
                    albums.addAll(albumArrayList);
                    albumsAdapter.notifyDataChanged();

                    albumsSpinner.setSelection(MatisseAbility.this, 0);

                    if (album.isAll() && SelectionSpec.getInstance().capture) {
                        album.addCaptureCount();
                    }

                    onAlbumSelected(album);
                }
            });
        }
    };


    /**
     * 图库列表
     */
    private final LoaderCallback<ResultSet> loaderCallback = new LoaderCallback<ResultSet>() {
        @Override
        public void setCallback(ResultSet resultSet) {
            handler.postTask(new Runnable() {
                @Override
                public void run() {
                    ArrayList<Item> list1 = new ArrayList<>();
                    if (resultSet.goToFirstRow()) {
                        do {
                            String type = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.MIME_TYPE));
                            if (album != null) {
                                if (MimeType.isVideo(type) || MimeType.isImage(type)) {
                                    if (!album.isAll()) {
                                        String data = resultSet.getString(resultSet.getColumnIndexForName(AVStorage.AVBaseColumns.DATA));
                                        int last = data.lastIndexOf("/");
                                        if (last >= 0) {
                                            String lastString = data.substring(0, last);

                                            int last2 = lastString.lastIndexOf("/");
                                            String lastString2 = lastString.substring(last2 + 1);
                                            if (album.getDisplayName(MatisseAbility.this).equals(lastString2)) {
                                                Item item = Item.valueOf(resultSet);
                                                list1.add(item);
                                            }
                                        }

                                    } else {
                                        Item item = Item.valueOf(resultSet);
                                        list1.add(item);
                                    }
                                }

                            } else {
                                if (MimeType.isVideo(type) || MimeType.isImage(type)) {
                                    Item item = Item.valueOf(resultSet);
                                    list1.add(item);
                                }
                            }

                        } while (resultSet.goToNextRow());
                    }
                    resultSet.close();

                    if (list1.isEmpty()) {
                        emptyLayout.setVisibility(Component.VISIBLE);
                        listContainer.setVisibility(Component.HIDE);
                        list.clear();
                    } else {
                        emptyLayout.setVisibility(Component.HIDE);
                        listContainer.setVisibility(Component.VISIBLE);
                        list.clear();
                        list.addAll(list1);

                    }

                    provider.notifyDataChanged();
                }
            });
        }
    };

    private final EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());

    @Override
    protected void onStop() {
        super.onStop();
        if (loader != null) {
            loader.cancel(true);
        }
        if (albumLoader != null) {
            albumLoader.cancel(true);
        }
        handler.removeAllEvent();
    }

    private void clickListener(Component component){
        int id = component.getId();
        if (id == ResourceTable.Id_imageMatisse_back) {
            terminateAbility();
        } else if (id == ResourceTable.Id_dlCheckMatisse) {
            int count = countOverMaxSize();
            if (count > 0){
                IncapableDialog incapableDialog = new IncapableDialog(getContext());
                try {
                    incapableDialog.setMessage(getResourceManager().getElement(ResourceTable.String_error_over_original_count).getString(count,mSpec.originalMaxSize));
                } catch (IOException | NotExistException | WrongTypeException e) {
                    incapableDialog.setMessage(String.format("%1$d images over %2$d MB. Original will be unchecked",count,mSpec.originalMaxSize));
                }
                incapableDialog.setPositiveButton().show();
            }
            mOriginalEnable = !mOriginalEnable;
            checkRadioView.setChecked(mOriginalEnable);
            textCheck.setTextColor(new Color(mOriginalEnable ? mSelectedColor : mUnSelectUdColor));

            if (mSpec.onCheckedListener != null){
                mSpec.onCheckedListener.onCheck(mOriginalEnable);
            }
        } else if (id == ResourceTable.Id_textMatisse_apply) {
            Intent result = new Intent();
            ArrayList<Uri> selectedUris = (ArrayList<Uri>) mSelectedCollection.asListOfUri();
            result.setSequenceableArrayListParam(EXTRA_RESULT_SELECTION, selectedUris);
            ArrayList<String> selectedPaths = (ArrayList<String>) mSelectedCollection.asListOfString();
            result.setStringArrayListParam(EXTRA_RESULT_SELECTION_PATH, selectedPaths);
            result.setParam(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable);
            setResult(RESULT_OK, result);
            terminateAbility();
        } else if (id == ResourceTable.Id_textMatisse_preview) {
            Intent intent = new Intent();
            intent.setSequenceableArrayListParam(STATE_SELECTION, new ArrayList<>(mSelectedCollection.getItems()));
            intent.setParam(STATE_COLLECTION_TYPE, mSelectedCollection.getCollectionType());
            intent.setParam(BasePreviewAbility.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable);
            Operation operation = new Intent.OperationBuilder()
                    .withDeviceId("")
                    .withBundleName(getBundleName())
                    .withAbilityName(SelectPreviewAbility.class.getName())
                    .build();
            intent.setOperation(operation);
            startAbilityForResult(intent, MatisseAbility.REQUEST_CODE_PREVIEW);
        }
    }

    @Override
    public void onItemSelected(ListContainer listContainer, Component component, int position, long id) {
        album = (Album) albumsAdapter.getItem(position);
        if (album.isAll() && SelectionSpec.getInstance().capture) {
            album.addCaptureCount();
        }
        onAlbumSelected(album);
    }

    private boolean isAll = true;

    private void onAlbumSelected(Album album) {
        isAll = album.isAll();
        loader = new ResultSetLoader(MatisseAbility.this, SelectionSpec.getInstance().capture);
        loader.setLoaderCallback(loaderCallback);
        loader.load();
    }

    @Override
    public void onNothingSelected(ListContainer listContainer) {
        //Oop
    }

    @Override
    public void onMediaSelect(Album album, Item item, int adapterPosition) {
        if (item.isCapture()) {
            Intent i = new Intent();
            Operation operation = new Intent.OperationBuilder()
                    .withDeviceId("")
                    .withBundleName(getBundleName())
                    .withAbilityName(CameraAbility.class.getName())
                    .build();
            i.setOperation(operation);
            startAbilityForResult(i, CameraAbility.REQUEST_CODE);
        } else {
            Intent i = new Intent();
            ArrayList<Item> list = new ArrayList<>(provider.getList());
            if (mSpec.capture) {
                list.remove(0);
            }
            i.setSequenceableArrayListParam(AlbumPreviewAbility.EXTRA_ALBUM_LIST, list);
            i.setSequenceableArrayListParam(STATE_SELECTION, new ArrayList<>(mSelectedCollection.getItems()));
            i.setParam(STATE_COLLECTION_TYPE, mSelectedCollection.getCollectionType());
            if (isAll && mSpec.capture) {
                i.setParam("index", adapterPosition - 1);
            } else {
                i.setParam("index", adapterPosition);
            }

            i.setParam(BasePreviewAbility.EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable);
            Operation operation = new Intent.OperationBuilder()
                    .withDeviceId("")
                    .withBundleName(getBundleName())
                    .withAbilityName(AlbumPreviewAbility.class.getName())
                    .build();
            i.setOperation(operation);
            startAbilityForResult(i, MatisseAbility.REQUEST_CODE_PREVIEW);
        }
    }

    @Override
    protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) {
        super.onAbilityResult(requestCode, resultCode, resultData);
        if (resultCode != RESULT_OK) {
            return;
        }
        try {
            if (resultData != null) {
                switch (requestCode) {
                    case CameraAbility.REQUEST_CODE: {
                        ArrayList<Uri> selected = new ArrayList<>();
                        ArrayList<String> selectedPath = new ArrayList<>();
                        selectedPath.add(resultData.getStringParam(CameraAbility.REQUEST_FILE_PATH));
                        selected.add(resultData.getSequenceableParam(CameraAbility.REQUEST_URI));
                        Intent result = new Intent();
                        result.setSequenceableArrayListParam(EXTRA_RESULT_SELECTION, selected);
                        result.setStringArrayListParam(EXTRA_RESULT_SELECTION_PATH, selectedPath);
                        setResult(RESULT_OK, result);
                        terminateAbility();
                    }
                    break;
                    case REQUEST_CODE_PREVIEW:
                        ArrayList<Item> selected = resultData.getSequenceableArrayListParam(SelectedItemCollection.STATE_SELECTION);
                        mOriginalEnable = resultData.getBooleanParam(BasePreviewAbility.EXTRA_RESULT_ORIGINAL_ENABLE, false);
                        int collectionType = resultData.getIntParam(SelectedItemCollection.STATE_COLLECTION_TYPE,
                                SelectedItemCollection.COLLECTION_UNDEFINED);
                        if (resultData.getBooleanParam(BasePreviewAbility.EXTRA_RESULT_APPLY, false)) {
                            Intent result = new Intent();
                            ArrayList<Uri> selectedUris = new ArrayList<>();
                            ArrayList<String> selectedPaths = new ArrayList<>();
                            if (selected != null) {
                                for (Item item : selected) {
                                    selectedUris.add(item.getContentUri());
                                    selectedPaths.add(item.data);
                                }
                            }
                            result.setSequenceableArrayListParam(EXTRA_RESULT_SELECTION, selectedUris);
                            result.setStringArrayListParam(EXTRA_RESULT_SELECTION_PATH, selectedPaths);
                            result.setParam(EXTRA_RESULT_ORIGINAL_ENABLE, mOriginalEnable);
                            setResult(RESULT_OK, result);
                            terminateAbility();
                        } else {
                            mSelectedCollection.overwrite(selected, collectionType);
                            provider.notifyDataChanged();
                            updateBottomToolbar();
                        }
                        break;

                    default:
                        break;
                }
            }
        }catch (Exception e){
            throw new ClassCastException("Class Exception");
        }

    }

    @Override
    public void onUpdate() {
        updateBottomToolbar();

        if (mSpec.onSelectedListener != null) {
            mSpec.onSelectedListener.onSelected(
                    mSelectedCollection.asListOfUri(), mSelectedCollection.asListOfString());
        }
    }

    private void updateBottomToolbar() {

        int selectedCount = mSelectedCollection.count();
        if (selectedCount == 0) {
            tvPreview.setEnabled(false);
            try {
                tvApply.setText(getResourceManager().getElement(ResourceTable.String_button_apply_default).getString());
                tvApply.setTextColor(new Color(getResourceManager().getElement(ResourceTable.Color_zhihu_bottom_toolbar_apply_text_disable).getColor()));
                tvPreview.setTextColor(new Color(getResourceManager().getElement(ResourceTable.Color_zhihu_bottom_toolbar_preview_text_disable).getColor()));
            } catch (IOException | NotExistException | WrongTypeException e) {

                tvApply.setText("Apply");
                tvApply.setTextColor(new Color(0x4D0077D9));
                tvPreview.setTextColor(new Color(0x4D000000));
            }
            tvApply.setEnabled(false);
        } else if (selectedCount == 1 && mSpec.singleSelectionModeEnabled()) {
            tvPreview.setEnabled(true);
            try {
                tvApply.setText(getResourceManager().getElement(ResourceTable.String_button_apply_default).getString());
                tvApply.setTextColor(new Color(getResourceManager().getElement(ResourceTable.Color_zhihu_bottom_toolbar_apply_text).getColor()));
                tvPreview.setTextColor(new Color(getResourceManager().getElement(ResourceTable.Color_zhihu_bottom_toolbar_preview_text).getColor()));
            } catch (IOException | NotExistException | WrongTypeException e) {

                tvApply.setText("Apply");
                tvApply.setTextColor(new Color(0x0077D9));
                tvPreview.setTextColor(new Color(0xDE000000));
            }
            tvApply.setEnabled(true);
        } else {
            tvPreview.setEnabled(true);
            tvApply.setEnabled(true);
            try {
                tvApply.setText(getResourceManager().getElement(ResourceTable.String_button_apply).getString(selectedCount));
                tvApply.setTextColor(new Color(getResourceManager().getElement(ResourceTable.Color_zhihu_bottom_toolbar_apply_text).getColor()));
                tvPreview.setTextColor(new Color(getResourceManager().getElement(ResourceTable.Color_zhihu_bottom_toolbar_preview_text).getColor()));
            } catch (IOException | NotExistException | WrongTypeException e) {
                tvApply.setText("Apply");
                tvApply.setTextColor(new Color(0x0077D9));
                tvPreview.setTextColor(new Color(0xDE000000));
            }
        }

        if (mSpec.originalable) {
            dlCheck.setVisibility(Component.VISIBLE);
            updateOriginalState();
        } else {
            dlCheck.setVisibility(Component.INVISIBLE);
        }


    }

    private void updateOriginalState() {
        checkRadioView.setChecked(mOriginalEnable);
        if (countOverMaxSize() > 0) {

            if (mOriginalEnable) {
                IncapableDialog incapableDialog = new IncapableDialog(getContext());
                try {
                    incapableDialog.setMessage(getResourceManager().getElement(ResourceTable.String_error_over_original_size).getString(mSpec.originalMaxSize));
                } catch (IOException | NotExistException | WrongTypeException e) {
                    incapableDialog.setMessage(String.format("Can\\'t select the images larger than %1$d MB", mSpec.originalMaxSize));
                }
                incapableDialog.setPositiveButton().show();

                checkRadioView.setChecked(false);
                mOriginalEnable = false;
            }
        }
    }

    private int countOverMaxSize() {
        int count = 0;
        int selectedCount = mSelectedCollection.count();
        for (int i = 0; i < selectedCount; i++) {
            Item item = mSelectedCollection.asList().get(i);

            if (item.isImage()) {
                float size = PhotoMetadataUtils.getSizeInMB(item.size);
                if (size > mSpec.originalMaxSize) {
                    count++;
                }
            }
        }
        return count;
    }
}
